package org.shan.lis.common.serial;

import gnu.io.SerialPort;
import org.shan.lis.utils.LogUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class Serial implements ISender {
    private SerialParameters serialParameters;
    private SerialPort serialPort;
    private InputStream recvStream;
    private OutputStream sendStream;
    private boolean open = false; // 串口是否已经打开
    private boolean occupy = false; // 串口损坏

    private IReciver reciver;
    private ReciveDataRunnable reciveDataRunnable;


    public Serial(String portName) {
        this(portName, 9600);
    }

    public Serial(String portName, int baudRate) {
        this(portName, baudRate, SerialPort.PARITY_NONE);
    }

    public Serial(String portName, int baudRate, int parity) {
        this(portName, baudRate, parity, SerialPort.FLOWCONTROL_NONE);
    }

    public Serial(String portName, int baudRate, int parity, int flowControlIn) {
        serialParameters = new SerialParameters();
        serialParameters.setPortName(portName);
        serialParameters.setBaudRate(baudRate);
        serialParameters.setParity(parity);
        serialParameters.setFlowControlIn(flowControlIn);
    }

    public Serial(String portName, IReciver reciver) {
        this(portName);
        this.reciver = reciver;
    }

    public Serial(String portName, int baudRate, IReciver reciver) {
        this(portName, baudRate);
        this.reciver = reciver;
    }

    public void setReciver(IReciver reciver) {
        this.reciver = reciver;
    }

    public boolean openSerialPort() {
        if (open) {
            return true;
        }
        serialPort = SerialFactory.openSerial(serialParameters);
        if (serialPort == null) {
            LogUtils.e(getClass().getName() + " serialPort == null openSerial error");
            occupy = true;
            return false;
        }
        printSerialInfo();

        try {
            recvStream = serialPort.getInputStream();
            sendStream = serialPort.getOutputStream();
            startRevice();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }

        open = true;
        occupy = false;

        return true;
    }

    private void printSerialInfo(){

        StringBuilder builder = new StringBuilder();
        builder.append("name:"+serialPort.getName()+"\n");
        builder.append("波特率:"+serialPort.getBaudRate()+"\n");
        builder.append("流控:"+serialPort.getFlowControlMode()+"\n");
        builder.append("DataBits:"+serialPort.getDataBits()+"\n");
        builder.append("Parity:"+serialPort.getParity()+"\n");
        builder.append("StopBits:"+serialPort.getStopBits()+"\n");

        LogUtils.d(builder.toString());
    }


    public void closeSerialPort() {
        if (!open)
            return;

        if (serialPort != null) {
            try {
                // close the i/o streams.
                recvStream.close();
                sendStream.close();
                stopRevice();
            } catch (IOException e) {
                System.err.println(e);
            }

            // Close the port.
            serialPort.close();

        }
        open = false;

    }

    private void startRevice() {
        if (reciveDataRunnable == null) {
            reciveDataRunnable = new ReciveDataRunnable(recvStream, reciver);
            new Thread(reciveDataRunnable).start();
        }
    }

    private void stopRevice() {
        if (reciveDataRunnable != null) {
            reciveDataRunnable.stop();
            reciveDataRunnable = null;
        }
    }

    public boolean isOccupy() {
        return occupy;
    }

    public boolean IsOpen() {
        return open;
    }

    public SerialParameters getSerialParameters() {
        return serialParameters;
    }

    public void setSerialParameters(SerialParameters serialParameters) {
        this.serialParameters = serialParameters;
        if (open)
            SerialFactory.SetSerialParams(serialPort, serialParameters);
    }

    public void setSerialParameters() {
        if (open)
            SerialFactory.SetSerialParams(serialPort, serialParameters);
    }

    public String getPortName() {
        return serialParameters.getPortName();
    }

    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub

        if (this == obj)
            return true;

        if (!(obj instanceof Serial))
            return false;
        Serial serial = (Serial) obj;

        if (this.serialParameters.getPortName().equals(serial.getPortName()))
            return true;
        else
            return false;
    }

    @Override
    public synchronized void send(byte[] bs) throws IOException {
        sendStream.write(bs);
    }

}
